#include <klayout_utils/klayout_utils.h>
#include <qlib/utils/font.h>
#include <qlib/utils/fontSrc.h>

namespace qlib {

const Vec2dArray& debug_font() {
  static bool first = true;
  static Vec2dArray real_all;
  if (first) {
    first = false;
    real_all.clear();

    int size = sizeof(t_all_coords) / sizeof(t_all_coords[0]);
    int count = 0;

    real_all.resize(size / 2);
    for (size_t i = 0; i < size; i++) {
      if (i % 2 == 0) {
        real_all[count].x = t_all_coords[i].x;
      } else {
        real_all[count].y = t_all_coords[i].x;
        count++;
      }
    }
  }
  return real_all;
}

Vec2d getAnchorTrans(Vec2d pos, Vec2dArray box, Anchor anchor) {
  Vec2d nowPos = (box[0] + box[1]) / 2.0;

  if (anchor == Anchor::O) {
    nowPos = (box[0] + box[1]) / 2.0;
  }

  if (anchor == Anchor::N) {
    nowPos.y = box[1].y;
  }
  if (anchor == Anchor::S) {
    nowPos.y = box[0].y;
  }

  if (anchor == Anchor::W) {
    nowPos.x = box[0].x;
  }
  if (anchor == Anchor::E) {
    nowPos.x = box[1].x;
  }

  if (anchor == Anchor::NW) {
    nowPos.x = box[0].x;
    nowPos.y = box[1].y;
  }
  if (anchor == Anchor::NE) {
    nowPos.x = box[1].x;
    nowPos.y = box[1].y;
  }

  if (anchor == Anchor::SW) {
    nowPos.x = box[0].x;
    nowPos.y = box[0].y;
  }
  if (anchor == Anchor::SE) {
    nowPos.x = box[1].x;
    nowPos.y = box[0].y;
  }

  return pos - nowPos;
}

Vec2dArray get_text(std::string text, Vec2d baseline, double size, double angle, Anchor anchor) {
  auto lines = KlU::text_test(text, KlU::Point{baseline.x, baseline.y}, size, angle, int(anchor));
  Vec2dArray points;
  points.reserve(lines.size());
  for (auto p : lines) {
    points.push_back(Vec2d(p.x, p.y));
  }

  return points;
}

std::vector<Vec2dArray> getStrPoints(std::string text, Anchor anchor, Vec2d position, double size, double rotation, FontType type) {
  if (type == FontType::Gdstk) {
    size /= 16;
    Vec2d cursor = position;
    const char* s = text.c_str();
    bool vertical = false;

    const Vec2dArray& _all_coords = debug_font();

    std::vector<Vec2dArray> result;

    Vec2d min;
    Vec2d max;

    min.x = min.y = DBL_MAX;
    max.x = max.y = -DBL_MAX;

    for (; *s != 0; s++) {
      switch (*s) {
        case 0x20:  // Space
          if (vertical)
            cursor.y -= size * VERTICAL_STEP;
          else
            cursor.x += size * HORIZONTAL_STEP;
          break;
        case 0x09:  // Horizontal tab
          if (vertical)
            cursor.y += size * VERTICAL_TAB;
          else
            cursor.x += size * HORIZONTAL_TAB;
          break;
        case 0x0A:  // Carriage return
          if (vertical) {
            cursor.y = position.y;
            cursor.x += size * VERTICAL_LINESKIP;
          } else {
            cursor.x = position.x;
            cursor.y -= size * HORIZONTAL_LINESKIP;
          }
          break;
        default: {
          const int32_t index = *s - FIRST_CODEPOINT;
          if (index >= 0 && index < (int32_t)(COUNT(_first_poly))) {
            uint16_t p_idx = _first_poly[index];
            for (uint16_t i = _num_polys[index]; i > 0; i--, p_idx++) {
              Vec2dArray points;
              points.reserve(_num_coords[p_idx]);

              uint16_t c_idx = _first_coord[p_idx];
              for (uint16_t j = _num_coords[p_idx]; j > 0; j--, c_idx++) {
                points.push_back(cursor + _all_coords[c_idx] * size);

                auto p = points.back();
                if (p.x < min.x) {
                  min.x = p.x;
                }
                if (p.x > max.x) {
                  max.x = p.x;
                }
                if (p.y < min.y) {
                  min.y = p.y;
                }
                if (p.y > max.y) {
                  max.y = p.y;
                }
              }
              result.push_back(points);
            }
            if (vertical)
              cursor.y -= size * VERTICAL_STEP;
            else
              cursor.x += size * HORIZONTAL_STEP;
          }
        }
      }
    }

    Vec2dArray box(2);
    box[0] = min;
    box[1] = max;

    Vec2d trans = getAnchorTrans(position, box, anchor);
    for (auto& points : result) {
      for (auto& p : points) {
        p += trans;
      }
    }

    double ca = cos(rotation);
    double sa = sin(rotation);

    Vec2d pt;

    for (auto& points : result) {
      for (auto& p : points) {
        pt = p - position;
        p.x = pt.x * ca - pt.y * sa + position.x;
        p.y = pt.x * sa + pt.y * ca + position.y;
      }
    }

    return result;
  }

  if (type == FontType::FreeType) {
    std::vector<Vec2dArray> result;

    return result;
  }
}

}  // namespace qlib